home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / mail / mh / vmail / vmail.3of3.Z / vmail.3of3 / load.c
Encoding:
C/C++ Source or Header  |  1991-04-05  |  11.6 KB  |  515 lines

  1. #ifndef lint
  2. static char *RCS_load_c = "$Id: load.c,v 1.5 90/07/31 11:29:15 rogers Exp $";
  3. #endif
  4.  
  5. /* --------------------
  6.     vmail -- load.c
  7.  
  8.     Routines to find folders, find all mail items in folders.  Empty
  9.     folders are ignored.
  10.  
  11.     Copyright (C) J. Zobel, University of Melbourne, October 1987.
  12. -------------------- */
  13.  
  14. #include "defs.h"
  15. #include <ctype.h>
  16.  
  17.  
  18. /* --------------------
  19.     Find all folders in mail directory, set up linked list.
  20. -------------------- */
  21. void
  22. find_folders()
  23. {
  24.     struct direct *dp;
  25.     struct stat statbuf;
  26.     DIR        *dirp;
  27.     int        i, max = 0, n = 0, scmp();
  28.     char    str[LEN], **fds, **ftmp;
  29.     folder    tmp, last = (folder) NULL;
  30.  
  31.     (void)stat(mail_dir, &statbuf);
  32.         /* guess number of folders - 10 is an error bound */
  33.     max = statbuf.st_nlink+10;
  34. #ifdef sparc
  35.     ftmp = fds = (char **) memalign((unsigned)8, (unsigned)(sizeof(char *) * max));
  36. #else
  37.     ftmp = fds = (char **) malloc((unsigned)(sizeof(char *) * max));
  38. #endif
  39.     dirp = opendir(mail_dir);
  40.     for(dp=readdir(dirp) ; dp != (struct direct *)NULL ; dp=readdir(dirp)) {
  41.         if(strcmp(dp->d_name, ".") == 0)
  42.             continue;
  43.         if(strcmp(dp->d_name, "..") == 0)
  44.             continue;
  45.         (void)sprintf(str, "%s/%s", mail_dir, dp->d_name);
  46.         (void)stat(str, &statbuf);
  47.         if(! (statbuf.st_mode & S_IFDIR))
  48.             continue;
  49.         if(! (statbuf.st_mode & S_IREAD) || ! (statbuf.st_mode & S_IWRITE)
  50.                 || ! (statbuf.st_mode & S_IEXEC)) {
  51.             (void)printf("Folder %s unreadable.\n", dp->d_name);
  52.             continue;
  53.         }
  54.         if(n == max){
  55.             int offset = ftmp - fds;    /* how far into fds    */
  56.  
  57.             /*
  58.              * We just overflowed the guessed number of entries
  59.              * Let's try 10 more.
  60.              */
  61.             max += 10;
  62.             fds = (char **)realloc((char *)fds, (unsigned)(sizeof(char *) * max));
  63.             ftmp = fds + offset;
  64.         }
  65.  
  66.         *ftmp = NEWSTR(strlen(dp->d_name)+1);
  67.         (void)strcpy(*ftmp, dp->d_name);
  68.         n++, ftmp++;
  69.     }
  70.     (void)closedir(dirp);
  71.     if(n == 0) {
  72.         (void)printf("No folders.\n");
  73.         exit(1);
  74.     }
  75.     qsort((char *)fds, n, sizeof(char *), scmp);
  76.     for(i=0, ftmp=fds ; i < n ; ftmp++, i++) {
  77.         tmp = NEW(mail_folder);
  78.         tmp->name = *ftmp;
  79.         tmp->last = tmp->mail = (item) NULL;
  80.         tmp->pages = tmp->pagenum = 1;
  81.         tmp->valid = false;
  82.         tmp->prev = last;
  83.         tmp->next = (folder) NULL;
  84.         if(last != (folder) NULL)
  85.             last->next = tmp;
  86.         else
  87.             folders = tmp;
  88.         last = tmp;
  89.     }
  90. }
  91.  
  92.  
  93. int
  94. scmp(p, q)
  95.     char    **p, **q;
  96. {
  97.     return(strcmp(*p, *q));
  98. }
  99.  
  100.  
  101. /* --------------------
  102.     Find all mail items in given folder, throw away folder record if no
  103.     mail items.  Returns next folder in linked list, adds new folder
  104.     records to linked list if original record overflows.
  105. -------------------- */
  106. folder
  107. find_mail(flr, load_time)
  108.     folder    flr;
  109.     int        load_time;
  110. {
  111.     struct direct *dp, *readdir();
  112.     DIR        *dirp, *opendir();
  113.     int        i, n = 0, items[MAXITEMS], *itmp = items, dcmp();
  114.     char    str[LEN];
  115.     item    tmp, last = (item) NULL;
  116.     folder    new_folder();
  117.  
  118.     (void)sprintf(str, "%s/%s", mail_dir, flr->name);
  119.     dirp = opendir(str);
  120.     if(dirp == (DIR *) NULL) {
  121.         if(load_time)
  122.             (void)printf("%s: strange folder.\n", str);
  123.     } else {
  124.         for(dp=readdir(dirp) ; dp!=(struct direct *) NULL ; dp=readdir(dirp)) {
  125.                     /* get numbers of all mail items */
  126.             if(n >= MAXITEMS) {
  127.                 no_control();
  128.                 (void)printf("\nMore than %d items in folder.\n",MAXITEMS-1);
  129.                 exit(1);
  130.             }
  131.                 /* ignore anything that is not string of digits */
  132.             if(! digits(dp->d_name))
  133.                 continue;
  134.                     /* assume any file that is string of digits is a mail
  135.                        item and not a directory */
  136.             *itmp = atoi(dp->d_name);
  137.             n++, itmp++;
  138.         }
  139.         (void)closedir(dirp);
  140.     }
  141.     if(n == 0) {        /* Empty folder - delete from list */
  142.         flr->valid = EMPTY;
  143.         if(load_time)
  144.             (void)printf("\t%s: empty\n", flr->name);
  145.         if(flr->prev != (folder) NULL)
  146.             flr->prev->next = flr->next;
  147.         else
  148.             folders = flr->next;
  149.         if(flr->next != (folder) NULL)
  150.             flr->next->prev = flr->prev;
  151.         return(flr->next);
  152.     } else
  153.         qsort((char *)items, n, sizeof(int), dcmp);
  154.     if(load_time)        /* show status of folder */
  155.         if(n == 1)
  156.             (void)printf("\t%s: %d\n", flr->name, *items);
  157.         else
  158.             (void)printf("\t%s: %d-%d (%d items)\n",flr->name,*items,*(items+n-1),n);
  159.     for(i=0, itmp=items ; i < n ; itmp++, i++) {
  160.             /* add item to list of items in folder */
  161.         tmp = NEW(mail_item);
  162.         get_title(flr, tmp, *itmp);
  163.         if(i % lines == 0 && last != (item) NULL) {
  164.                 /* add new record for folder */
  165.             flr->last = last;
  166.             flr = new_folder(flr);
  167.             last = (item) NULL;
  168.         }
  169.         tmp->next = (item) NULL;
  170.         tmp->prev = last;
  171.         if(last != (item) NULL)
  172.             last->next = tmp;
  173.         else
  174.             flr->mail = tmp;
  175.         last = tmp;
  176.     }
  177.     flr->last = last;
  178.     return(flr->next);
  179. }
  180.  
  181.  
  182. int
  183. dcmp(a, b)
  184.     int        *a, *b;
  185. {
  186.     return(*a - *b);
  187. }
  188.  
  189.  
  190. /* --------------------
  191.     Return true if string consists only of digits.
  192. -------------------- */
  193. int
  194. digits(str)
  195.     char    *str;
  196. {
  197.     for( ; *str != '\0' ; str++)
  198.         if(! isdigit(*str))
  199.             return(false);
  200.     return(true);
  201. }
  202.  
  203.  
  204. /* --------------------
  205.     Make header line from mail item.
  206. -------------------- */
  207. void
  208. get_title(flr, mail, num)
  209.     folder    flr;
  210.     item    mail;
  211.     int        num;
  212. {
  213.     FILE    *fp, *fopen();
  214.     char    date[10], str[LEN], subj[42], from[20], to[16], fill[42];
  215.     char    repl = ' ', *first(), *s, *fgets();
  216.     int        i;
  217.  
  218.     subj[0] = from[0] = to[0] = fill[0] = '\0';
  219.     (void)sprintf(str, "%s/%s/%d", mail_dir, flr->name, num);
  220.     fp = fopen(str, "r");
  221.     while((s=fgets(str, LEN, fp)) != (char *) NULL && *str != '\n') {
  222.             /* while not eof and reading header */
  223.         str[strlen(str)-1] = '\0';
  224.             /* should also check date */
  225.         if(! lstrncmp("date:", str, 5))
  226.             get_date(str+5, date);
  227.         else if(! lstrncmp("subject:", str, 8)) {
  228.             s = first(str+8);
  229.             (void)strncpy(subj, s, 41);
  230.             subj[41] = '\0';
  231.         } else if(! lstrncmp("replied:", str, 8))
  232.             repl = '-';
  233.         else if(! lstrncmp("from:", str, 5)) {
  234.             s = first(str+5);
  235.             if(! isuser(s)) {
  236.                 (void)strncpy(from, s, 19);
  237.                 from[19] = '\0';
  238.             }
  239.         } else if(! lstrncmp("to:", str, 3)) {
  240.             s = first(str+3);
  241.             (void)strncpy(to, s, 15);
  242.             to[15] = '\0';
  243.         } else if(! lstrncmp("apparently-to:", str, 14)) {
  244.             s = first(str+14);
  245.             (void)strncpy(to, s, 15);
  246.             to[15] = '\0';
  247.         }
  248.     }
  249.     if(s != (char *) NULL) {
  250.         for(i=0 ; i < 42 && fgets(str, LEN, fp) != (char *) NULL ;) {
  251.             str[strlen(str)-1] = ' ';
  252.             (void)strncpy(fill+i, str, 42-i);
  253.             i += strlen(str);
  254.         }
  255.         fill[41] = '\0';
  256.     }
  257.     (void)fclose(fp);
  258.     if(subj[0] == '\0')
  259.         (void)strcpy(subj, "(none)");
  260.     flatten(subj);
  261.     flatten(fill);
  262.     if(from[0] == '\0')
  263.         (void)sprintf(str, "  %8s %cTo: %-15s  %s << %s",date,repl,to,subj,fill);
  264.     else
  265.         (void)sprintf(str, "  %8s %c%-19s  %s << %s",date,repl,from,subj,fill);
  266.     str[cols-6] = '\0';
  267.     mail->title = NEWSTR(strlen(str)+1);
  268.     mail->number = num;
  269.     (void)strcpy(mail->title, str);
  270. }
  271.  
  272.  
  273. #ifdef USDATE
  274. #define DAY1    date[3]
  275. #define DAY2    date[4]
  276. #define MTH1    date[0]
  277. #define MTH2    date[1]
  278. #else
  279. #define DAY1    date[0]
  280. #define DAY2    date[1]
  281. #define MTH1    date[3]
  282. #define MTH2    date[4]
  283. #endif
  284. #define YR1        date[6]
  285. #define YR2        date[7]
  286.  
  287. /* --------------------
  288.     Get date from first argument; assumes format is one of
  289. Date: Fri, 3 Apr 87 ...                        (a)
  290. Date: Wed, 17 Jun 87 ...                    (b)
  291. Date: 07 Sep 87 ...                            (c)
  292. Date: Tue Sep 29 12:27:01 EST 1987            (d)
  293.     Dates are put into Imperial form (dd-mm-yy), or US form (mm-dd-yy)
  294.     if -DUSDATE is set.
  295.  
  296.     This routine should be more flexible re: recognizing date formats.
  297. -------------------- */
  298. void
  299. get_date(str, date)
  300.     char    *str, *date;
  301. {
  302.     int        i;
  303.     bool    get_month();
  304.     char    *next_token();
  305.  
  306.     date[2] = date[5] = '-';
  307.     date[8] = '\0';
  308.     for(; *str == ' ' || *str == '\t' ; str++)
  309.         ;
  310.     if(*str == '\0')
  311.         goto unknown;
  312.     if(! isdigit(*str))        /* day of month not first field */
  313.         str = next_token(str);        /* skip day of week */
  314.     if(str == (char *) NULL + 1)
  315.         goto unknown;
  316.  
  317.     if(isdigit(*str)) {        /* one of (a), (b) or (c) formats */
  318.         if(isdigit(*(str+1)))    /* two-number date */
  319. #ifdef USDATE
  320.             DAY1 = *str, DAY2 = *(++str);
  321.         else
  322.             DAY1 = '0', DAY2 = *str;
  323. #else
  324.             DAY1 = (*str == '0') ? ' ' : *str, DAY2 = *(++str);
  325.         else
  326.             DAY1 = ' ', DAY2 = *str;
  327. #endif
  328.         str = next_token(str);    /* go to month */
  329.         if(str == (char *) NULL + 1)
  330.             goto unknown;
  331.         if(! get_month(str, date))
  332.             goto unknown;
  333.         str = next_token(str);    /* go to year */
  334.         if(str == (char *) NULL + 1)
  335.             goto unknown;
  336.         if(! isdigit(*str) || ! isdigit(*(str+1)))
  337.             goto unknown;
  338.         YR1 = *str, YR2 = *(str+1);
  339.     } else {    /* format (d) */
  340.         if(! get_month(str, date))
  341.             goto unknown;
  342.         str = next_token(str);    /* go to day */
  343.         if(str == (char *) NULL + 1)
  344.             goto unknown;
  345.         if(! isdigit(*str) || ! isdigit(*(str+1)))
  346.             goto unknown;
  347. #ifdef USDATE
  348.         DAY1 = *str, DAY2 = *(++str);
  349. #else
  350.         DAY1 = (*str == '0') ? ' ' : *str, DAY2 = *(++str);
  351. #endif
  352.         str += strlen(str) - 2;        /* go to year */
  353.         if(! isdigit(*str) || ! isdigit(*(str+1)))
  354.             goto unknown;
  355.         YR1 = *str, YR2 = *(str+1);
  356.     }
  357.     return;        /* date is ok */
  358.  
  359. unknown:            /* erase date */
  360.     for(i=0 ; i < 8 ; i++)
  361.         date[i] = ' ';
  362. }
  363.  
  364.  
  365. static char *month[] = {
  366.     "jan", "feb", "mar", "apr", "may", "jun",
  367.     "jul", "aug", "sep", "oct", "nov", "dec"
  368. };
  369.  
  370. /* --------------------
  371.     Put the month from the first part of str in date as a number.
  372. -------------------- */
  373. bool
  374. get_month(str, date)
  375.     char    *str, *date;
  376. {
  377.     int        i;
  378.  
  379.     for(i=0 ; i < 12 && lstrncmp(month[i], str, 3) != 0 ; i++)
  380.         ;
  381.     if(i == 12)        /* string doesn't match month */
  382.         return(false);
  383.     else {    
  384.         if(i < 9)    /* single digit month */
  385. #ifdef USDATE
  386.             MTH1 = ' ', MTH2 = i + '0' + 1;
  387. #else
  388.             MTH1 = '0', MTH2 = i + '0' + 1;
  389. #endif
  390.         else
  391.             MTH1 = '1', MTH2 = i + '0' - 9;
  392.         return(true);
  393.     }
  394. }
  395.  
  396.  
  397. /* --------------------
  398.     Replace tabs and newlines in string by spaces.
  399.     Compress multiple spaces to a single space.
  400. -------------------- */
  401. void
  402. flatten(str)
  403.     char    *str;
  404. {
  405.     char    prev = ' ', *s = str;
  406.  
  407.     /* advance str monotonically, copying into s as necessary */
  408.  
  409.     while (*str)
  410.     {
  411.         /* change funny character to space */
  412.         if (!isgraph(*str)) {
  413.         *str = ' ';
  414.         }
  415.  
  416.         /* copy character into new position */
  417.         *s = *str;
  418.  
  419.         /* advance new string pointer, but compress multiple spaces */
  420.         if (isgraph(*str) || prev != ' ') {
  421.         prev = *s;
  422.         s++;
  423.         }
  424.         str++;
  425.     }
  426.     *s = '\0';
  427. }
  428.  
  429.  
  430. /* --------------------
  431.     Return pointer to first non-white character in string.
  432. -------------------- */
  433. char *
  434. first(str)
  435.     char    *str;
  436. {
  437.     for(; *str == ' ' || *str == '\t' || *str == '\n' ; str++)
  438.         ;
  439.     return(str);
  440. }
  441.  
  442.  
  443. /* --------------------
  444.     Check given string for occurence of user's name.
  445. -------------------- */
  446. int
  447. isuser(str)
  448.     char    *str;
  449. {
  450.     int        len = strlen(user);
  451.  
  452.     for(; *str != '\0' ; str++)
  453.             /* assume all chars in all unames alphanumeric */
  454.         if(*str == *user && strncmp(str, user, len) == 0 &&
  455.                 (*(str+len) < 'a' || *(str+len) > 'z') &&
  456.                 (*(str+len) < 'A' || *(str+len) > 'Z') &&
  457.                 (*(str+len) < '0' || *(str+len) > '9'))
  458.             return(true);
  459.     return(false);
  460. }
  461.  
  462.  
  463. /* --------------------
  464.     Make a new folder record.
  465. -------------------- */
  466. folder
  467. new_folder(flr)
  468.     folder    flr;
  469. {
  470.     folder    f;
  471.  
  472.     f = NEW(mail_folder);
  473.     f->prev = flr;
  474.     f->next = flr->next;
  475.     flr->next = f;
  476.     if(f->next != (folder) NULL)
  477.         f->next->prev = f;
  478.     f->pagenum = f->pages = flr->pages + 1;
  479.     f->name = flr->name;
  480.     f->valid = true;
  481.     f->mail = f->last = (item) NULL;
  482.     flr = f;
  483.     for(f=f->prev; f != (folder) NULL && f->name == flr->name ; f=f->prev)
  484.         f->pages = flr->pages;
  485.     return(flr);
  486. }
  487.  
  488.  
  489. /* --------------------
  490.     Find next free slot in directory for mail item (that is, find next
  491.     unused number) -- structures in vmail may not be up to date if user
  492.     has initiated a "send" process.
  493. -------------------- */
  494. int
  495. next_vacant(flr)
  496.     folder    flr;
  497. {
  498.     struct direct *dp, *readdir();
  499.     DIR        *dirp, *opendir();
  500.     char    str[LEN];
  501.     int        i, n = 0;
  502.  
  503.     (void)sprintf(str, "%s/%s", mail_dir, flr->name);
  504.     dirp = opendir(str);
  505.     for(dp=readdir(dirp) ; dp != (struct direct *) NULL ; dp=readdir(dirp)) {
  506.             /* ignore anything that is not string of digits */
  507.         if(! digits(dp->d_name))
  508.             continue;
  509.         if((i = atoi(dp->d_name)) > n)
  510.             n = i;
  511.     }
  512.     (void)closedir(dirp);
  513.     return(n+1);
  514. }
  515.